/*
 * Copyright (c) 2017 22420103@QQ.COM 版权所有
 */
package com.lehe.service.impl;

import com.lehe.common.Contants;
import com.lehe.common.crypt.Md5Encrypt;
import com.lehe.common.utils.StringUtil;
import com.lehe.service.ISendRedpackService;
import org.apache.http.HttpEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.conn.ssl.SSLContexts;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import org.springframework.stereotype.Service;

import javax.net.ssl.SSLContext;
import java.io.*;
import java.security.KeyStore;
import java.util.*;

/**
 * 微信支付发送现金红包<br>
 *
 * @author 王丹
 * @FileName SendRedpackService.java<br>
 * @Language Java<br>
 * @date 2016-01-27<br>
 */
@Service
public class SendRedpackService extends AbstractService implements ISendRedpackService {

    private String clientIp = "127.0.0.1";

    @Override
    public boolean sendRedpack(String orderNo, String reOpenid, int totalAmt, int totalNum,
                               String wishing, String actName, String remark) {
        boolean ret = false;
        logger.info(String.format("微信支付发送现金红包：orderNo=%s,reOpenid=%s,totalAmt=%d,totalNum=%d,wishing=%s,actName=%s,remark=%s",
                orderNo, reOpenid, totalAmt, totalNum, wishing, actName, remark));
        if(StringUtil.isBlank(reOpenid) || totalAmt <=0 || totalNum<=0
                || StringUtil.isBlank(wishing) || StringUtil.isBlank(actName) || StringUtil.isBlank(remark)){
            logger.warn("请求参数不能为空");
            return false;
        }
        if(totalAmt > 20000 || totalAmt < 100){
            logger.warn("红包金额介于【1.00元-200.00元】之间");
            return false;
        }
        SortedMap<String, String> params = createMap(orderNo, reOpenid, totalAmt, totalNum,
                wishing, actName, remark);
        sign(params);
        String reqXml = buildReqXml(params);
        String respXml = post(reqXml);
        if(StringUtil.isNotBlank(respXml)){
            String returnCode = StringUtil.getTagText(respXml, "return_code");
            String resultCode = StringUtil.getTagText(respXml, "result_code");
            if("SUCCESS".equalsIgnoreCase(returnCode) && "SUCCESS".equalsIgnoreCase(resultCode)){
                ret = true;
            }
        }
        return ret;
    }

    private SortedMap<String, String> createMap(String orderNo, String reOpenid, int totalAmt, int totalNum,
                                                String wishing, String actName, String remark){
        SortedMap<String, String> params = new TreeMap<String, String>();
        //params.put("sign", "");
        if(StringUtil.isBlank(orderNo)){
            params.put("mch_billno", getRandomStr(28));
        }else {
            params.put("mch_billno", orderNo);
        }
        params.put("mch_id", Contants.PAY_MCH_ID);
        params.put("wxappid", Contants.APP_ID);
        params.put("send_name", Contants.PAY_SEND_NAME);
        params.put("re_openid", reOpenid);
        params.put("total_amount", String.valueOf(totalAmt));
        params.put("total_num", String.valueOf(totalNum));
        params.put("wishing", wishing);
        params.put("client_ip", clientIp);
        params.put("act_name", actName);
        params.put("remark", remark);
        params.put("nonce_str", getRandomStr(16));
        return params;
    }

    private void sign(SortedMap<String, String> params){
        Set<Map.Entry<String, String>> entrys = params.entrySet();
        Iterator<Map.Entry<String, String>> it = entrys.iterator();
        String paramStr = "";
        while (it.hasNext()){
            Map.Entry<String, String> entry = it.next();
            String key = entry.getKey();
            String value = entry.getValue();
            if(StringUtil.isNotBlank(value) && !"sign".equals(key) && !"key".equals(key)){
                paramStr += key + "=" + value + "&";
            }
        }
        paramStr += "key=" + Contants.PAY_KEY;
        String signStr = Md5Encrypt.md5(paramStr).toUpperCase();
        params.put("sign", signStr);
    }

    private String buildReqXml(SortedMap<String, String> params){
        StringBuilder sb = new StringBuilder();
        sb.append("<xml>");
        Set<Map.Entry<String, String>> entrys = params.entrySet();
        Iterator<Map.Entry<String, String>> it = entrys.iterator();
        while (it.hasNext()){
            Map.Entry<String, String> entry = it.next();
            sb.append("<" + entry.getKey() + ">");
            sb.append("<![CDATA[" + entry.getValue() + "]]>");
            sb.append("</" + entry.getKey() + ">");
        }
        sb.append("</xml>");
        return sb.toString();
    }

    // 随机生成16位字符串
    private String getRandomStr(int size) {
        String base = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
        Random random = new Random();
        StringBuffer sb = new StringBuffer();
        for (int i = 0; i < size; i++) {
            int number = random.nextInt(base.length());
            sb.append(base.charAt(number));
        }
        return sb.toString();
    }

    private String post(String reqXml){
        String retStr = "";
        FileInputStream instream = null;
        try {
            KeyStore keyStore  = KeyStore.getInstance("PKCS12");
            instream = new FileInputStream(new File(Contants.PAY_CERT_PATH));
            keyStore.load(instream, Contants.PAY_MCH_ID.toCharArray());
            SSLContext sslcontext = SSLContexts.custom()
                    .loadKeyMaterial(keyStore, Contants.PAY_MCH_ID.toCharArray())
                    .build();
            SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(
                    sslcontext,
                    new String[] { "TLSv1" },
                    null,
                    SSLConnectionSocketFactory.BROWSER_COMPATIBLE_HOSTNAME_VERIFIER);
            CloseableHttpClient httpclient = HttpClients.custom()
                    .setSSLSocketFactory(sslsf)
                    .build();
            HttpPost httpPost = new HttpPost(Contants.WE_CHAT_PAY_BASE);
            StringEntity stringEntity = new StringEntity(reqXml, Contants.CHARSET_UTF);
            httpPost.setEntity(stringEntity);
            logger.info("请求微信红包地址：" + httpPost.getURI());
            logger.info("请求微信报文：" + reqXml);
            CloseableHttpResponse response = httpclient.execute(httpPost);
            HttpEntity entity = response.getEntity();
            logger.info("微信响应状态" + response.getStatusLine());
            if(entity != null) {
                logger.debug("Response content length: " + entity.getContentLength());
                BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(entity.getContent()));
                String text;
                while ((text = bufferedReader.readLine()) != null) {
                    retStr += text;
                }
            }
            EntityUtils.consume(entity);
            response.close();
            httpclient.close();
            logger.info("微信响应报文：" + retStr);
        } catch (Exception e) {
            logger.error("微信前置调用微信服务：红包接口异常", e);
        }finally {
            if(null!=instream){
                try {
                    instream.close();
                } catch (IOException e) {
                }
            }
        }
        return retStr;
    }
}
